#!/bin/bash

TREE_DIR=${TREE_DIR:-}

# Support to specify multiple trees too, separated by space
for tree in $TREE_DIR; do
    tree_args="--tree $PWD/$tree $tree_args"
done

tree_l=$(printf "$PWD/%s " $TREE_DIR)
tree_l=${tree_l% }

tree_args=${tree_args% }

export TREE=${TREE:-$tree_l}
TREE_ARGS=${TREE_ARGS:-$tree_args}

YAML_TREE=$(printf "/%s," $TREE_DIR)
YAML_TREE="[${YAML_TREE%,}]"

BUCKET=${BUCKET:-}
GITHUB_REPO=${GITHUB_REPO:-mocaccinoOS/desktop}
IMAGE_REPOSITORY=${IMAGE_REPOSITORY:-}
MINIO_API_URL=${MINIO_API_URL:-}
MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-}
MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-}
DOCKER_REGISTRY=${DOCKER_REGISTRY:-}
DOCKER_USER=${DOCKER_USER:-}
DOCKER_PASS=${DOCKER_PASS:-}
SMART_BUILD=${SMART_BUILD:-true}
BUILD_PHASE=${BUILD_PHASE:-true}
CREATE_PHASE=${CREATE_PHASE:-false}
PRUNE_PHASE=${PRUNE_PHASE:-false}
TRACE_LOGS_BACKGROUND=${TRACE_LOGS_BACKGROUND:-true}
BACKEND=${BACKEND:-img}
DOCKER_HOST=${DOCKER_HOST:-}
PRIVILEGED=${PRIVILEGED:-true}
REF=${REF:-}
NAMESPACE=${NAMESPACE:-}
PKG_LIST=$(luet tree pkglist $TREE_ARGS -o json)
COMPRESSION_TYPE=${COMPRESSION_TYPE:-gzip}
K8S_SCHEDULER=${K8S_SCHEDULER:-}
NODE_SELECTOR=${NODE_SELECTOR:-}

prune() {
    allPacks=()
    for i in $(echo "$PKG_LIST" | jq -rc '.packages[]'); do
            PACKAGE_PATH=$(echo "$i" | jq -r ".path")
            PACKAGE_NAME=$(echo "$i" | jq -r ".name")
            PACKAGE_CATEGORY=$(echo "$i" | jq -r ".category")
            PACKAGE_VERSION=$(echo "$i" | jq -r ".version")
            allPacks+=( "$PACKAGE_NAME\-$PACKAGE_CATEGORY\-$PACKAGE_VERSION" )
    done
    echo "Pruning old packages from repository"
    for a in $(mc find minio-ci/$BUCKET --regex '.*.package.*|.*.metadata.yaml$' --json |  jq -r '.key' ); do

        # For each package in the tree, get the path where the spec resides
        # e.g. packages/acct-group/amavis/0/
        for t in ${allPacks[@]}; do

            if echo $a | grep -q $t; then
            continue 2
            fi
        done

    # echo "$a pending deletion"
    mc rm $a

    done
}

wait_packages() {
    # For each package in the tree, get the path where the spec resides
    # e.g. packages/acct-group/amavis/0/
    for i in $(echo "$PKG_LIST" | jq -rc '.packages[]'); do

        PACKAGE_PATH=$(echo "$i" | jq -r ".path")
        PACKAGE_NAME=$(echo "$i" | jq -r ".name")
        PACKAGE_CATEGORY=$(echo "$i" | jq -r ".category")
        PACKAGE_VERSION=$(echo "$i" | jq -r ".version")
        export JOB_NAME=$PACKAGE_NAME-$PACKAGE_CATEGORY-$PACKAGE_VERSION
        JOB_NAME=${JOB_NAME//[^a-zA-Z0-9]/}
        JOB_NAME=`echo -n $JOB_NAME | tr A-Z a-z`


        echo "Checking package $PACKAGE_CATEGORY/$PACKAGE_NAME @ $PACKAGE_VERSION is built"
        while ! ( [ $(mc ls minio-ci/$BUCKET/$PACKAGE_NAME\-$PACKAGE_CATEGORY\-$PACKAGE_VERSION.package | wc -l) != "0" ] )
        do
            echo "Package $PACKAGE_CATEGORY/$PACKAGE_NAME @ $PACKAGE_VERSION not uploaded yet, sleeping"
            JOB_STATE=$(kubectl get packagebuild -n $NAMESPACE $JOB_NAME -o json | jq -r '.status.state')
            if [[ "$JOB_STATE" == "Pending" ]] || [[ "$JOB_STATE" == "Running" ]]; then
                kubectl logs -f -c spec-build -n $NAMESPACE $JOB_NAME
            fi
            if [[ "$JOB_STATE" == "Failed" ]]; then
                kubectl logs -f -c spec-build -n $NAMESPACE $JOB_NAME
                echo "Job failed, exiting"
                exit 1
            fi
            if [[ "$JOB_STATE" == "Succeeded" ]]; then
                echo "Build succeded"
            fi
            sleep 20
        done

        echo "Package built, deleting job"
        kubectl delete packagebuild -n $NAMESPACE $JOB_NAME

    done
}

create_repo() {
    # Unsetting tree as it will be automatically filled by make create-repo
    unset TREE
    set -ex
    mkdir build || true
    mc mirror --exclude '*.gz' --exclude '*.zstd' minio-ci/$BUCKET/ build
    ls -liah build/
    make create-repo
    mc cp --recursive build/ minio-ci/$BUCKET/
    ls -liah build/
}

parallel_build() {

    local PACKS=$1
    # Send tasks in parallel, and wait for them
    for package in $PACKS; do
        IFS=/ read -a parts <<< $package
        PACKAGE_CATEGORY=${parts[0]}
        PACKAGE_NAME=${parts[1]}
        PACKAGE_VERSION=$(echo "$PKG_LIST" | jq -r ".packages[] | select(.name==\"$PACKAGE_NAME\" and .category==\"$PACKAGE_CATEGORY\").version")

        if [ $(mc ls minio-ci/$BUCKET/$PACKAGE_NAME\-$PACKAGE_CATEGORY\-$PACKAGE_VERSION.package | wc -l) != "0" ]; then
                echo "Package $PACKAGE_CATEGORY/$PACKAGE_NAME already present, skipping"
                continue
        fi


        export JOB_NAME=$PACKAGE_NAME-$PACKAGE_CATEGORY-$PACKAGE_VERSION
        JOB_NAME=${JOB_NAME//[^a-zA-Z0-9]/}
        JOB_NAME=`echo -n $JOB_NAME | tr A-Z a-z`

        if kubectl get pods -n $NAMESPACE $JOB_NAME; then
            JOB_STATE=$(kubectl get packagebuild -n $NAMESPACE $JOB_NAME -o json | jq -r '.status.state')
            if [[ "$JOB_STATE" == "Pending" ]] || [[ "$JOB_STATE" == "Running" ]]; then
                echo "Job for $PACKAGE_NAME already running , skipping"
                continue
            fi

            if [[ "$JOB_STATE" == "Failed" ]]; then
                echo "Current job failed, deleting"
                kubectl delete packagebuild -n $NAMESPACE $JOB_NAME
            fi
        fi

cat <<EOF | kubectl apply -n $NAMESPACE -f -
apiVersion: luet.k8s.io/v1alpha1
kind: PackageBuild
metadata:
    name: $JOB_NAME
    annotations:
      luet-k8s.io/retry: "5"
spec:
    annotations:
        k8s-resource-scheduler/burst-protect: "200"
    nodeSelector:
        $NODE_SELECTOR
    podScheduler: "$K8S_SCHEDULER"
    packageName: "$PACKAGE_CATEGORY/$PACKAGE_NAME@$PACKAGE_VERSION"
    repository: 
        url: "https://github.com/${GITHUB_REPO}.git"
        checkout: "$REF"
    storage:
        enabled: true
        url: "$MINIO_API_URL"
        secretKey: "$MINIO_SECRET_KEY"
        accessID: "$MINIO_ACCESS_KEY"
        bucket: "$BUCKET"
        path: ""
    options:
        pull: true
        push: true
        imageRepository: "$IMAGE_REPOSITORY" 
        onlyTarget: true
        compression: "$COMPRESSION_TYPE"
        privileged: $PRIVILEGED
        liveOutput: true
        backend: $BACKEND
        environment:
        - name: DOCKER_HOST
          value: "$DOCKER_HOST"
        tree: $YAML_TREE
    registry:
        enabled: true
        registry: "$DOCKER_REGISTRY"
        username: "$DOCKER_USER"
        password: "$DOCKER_PASS"
EOF
    done # Done tocompile

    wait_packages
}

smart_build() {

    local PACKS=$1

    echo "Computing build sequence for: $PACKS"
    BUILDSEQUENCE=$(FORMAT=json luet-parallel-tools-commondeps $PACKS)

    echo "Build sequence: $BUILDSEQUENCE"

    for i in $(echo "$BUILDSEQUENCE" | jq  -rc '.[][]'); do

        TOCOMPILE=$(echo "$i" | jq -rc '.[]'  | xargs echo)
        echo "Building $TOCOMPILE and waiting"

        # Send tasks in parallel, and wait for them
        for package in $TOCOMPILE; do
            IFS=/ read -a parts <<< $package
            PACKAGE_CATEGORY=${parts[0]}
            PACKAGE_NAME=${parts[1]}
            PACKAGE_VERSION=$(echo "$PKG_LIST" | jq -r ".packages[] | select(.name==\"$PACKAGE_NAME\" and .category==\"$PACKAGE_CATEGORY\").version")

            if [ $(mc ls minio-ci/$BUCKET/$PACKAGE_NAME\-$PACKAGE_CATEGORY\-$PACKAGE_VERSION.package | wc -l) != "0" ]; then
                    echo "Package $PACKAGE_CATEGORY/$PACKAGE_NAME already present, skipping"
                    continue 1
            fi

            export JOB_NAME=$PACKAGE_NAME-$PACKAGE_CATEGORY-$PACKAGE_VERSION
            JOB_NAME=${JOB_NAME//[^a-zA-Z0-9]/}
            JOB_NAME=`echo -n $JOB_NAME | tr A-Z a-z`

            if kubectl get pods -n $NAMESPACE $JOB_NAME; then
                JOB_STATE=$(kubectl get packagebuild -n $NAMESPACE $JOB_NAME -o json | jq -r '.status.state')
                if [[ "$JOB_STATE" == "Pending" ]] || [[ "$JOB_STATE" == "Running" ]]; then
                    echo "Job for $PACKAGE_NAME already running , skipping"
                    continue 1
                fi

                if [[ "$JOB_STATE" == "Failed" ]]; then
                    echo "Current job failed, deleting"
                    kubectl delete packagebuild -n $NAMESPACE $JOB_NAME
                fi
            fi

cat <<EOF | kubectl apply -n $NAMESPACE -f -
apiVersion: luet.k8s.io/v1alpha1
kind: PackageBuild
metadata:
    name: $JOB_NAME
    annotations:
      luet-k8s.io/retry: "5"
spec:
    nodeSelector:
        $NODE_SELECTOR
    annotations:
        k8s-resource-scheduler/burst-protect: "200"
    podScheduler: "$K8S_SCHEDULER"
    packageName: "$PACKAGE_CATEGORY/$PACKAGE_NAME@$PACKAGE_VERSION"
    repository: 
        url: "https://github.com/${GITHUB_REPO}.git"
        checkout: "$REF"
    storage:
        enabled: true
        url: "$MINIO_API_URL"
        secretKey: "$MINIO_SECRET_KEY"
        accessID: "$MINIO_ACCESS_KEY"
        bucket: "$BUCKET"
        path: ""
    options:
        pull: true
        push: true
        imageRepository: "$IMAGE_REPOSITORY" 
        onlyTarget: true
        compression: "$COMPRESSION_TYPE"
        tree: $YAML_TREE
        privileged: $PRIVILEGED
        liveOutput: true
        backend: $BACKEND
        environment:
        - name: DOCKER_HOST
          value: "$DOCKER_HOST"
    registry:
        enabled: true
        registry: "$DOCKER_REGISTRY"
        username: "$DOCKER_USER"
        password: "$DOCKER_PASS"
EOF

        done # Done tocompile

        # Now let's wait
        for package in $TOCOMPILE; do
            IFS=/ read -a parts <<< $package
            PACKAGE_CATEGORY=${parts[0]}
            PACKAGE_NAME=${parts[1]}
            PACKAGE_VERSION=$(echo "$PKG_LIST" | jq -r ".packages[] | select(.name==\"$PACKAGE_NAME\" and .category==\"$PACKAGE_CATEGORY\").version")

            export JOB_NAME=$PACKAGE_NAME-$PACKAGE_CATEGORY-$PACKAGE_VERSION
            JOB_NAME=${JOB_NAME//[^a-zA-Z0-9]/}
            JOB_NAME=`echo -n $JOB_NAME | tr A-Z a-z`

            echo "Checking package $PACKAGE_CATEGORY/$PACKAGE_NAME @ $PACKAGE_VERSION is built"
            while ! ( [ $(mc ls minio-ci/$BUCKET/$PACKAGE_NAME\-$PACKAGE_CATEGORY\-$PACKAGE_VERSION.package | wc -l) != "0" ] )
            do
                echo "Package $PACKAGE_CATEGORY/$PACKAGE_NAME @ $PACKAGE_VERSION not uploaded yet, sleeping"
                JOB_STATE=$(kubectl get packagebuild -n $NAMESPACE $JOB_NAME -o json | jq -r '.status.state')
                if [[ "$JOB_STATE" == "Pending" ]] || [[ "$JOB_STATE" == "Running" ]]; then
                    kubectl logs -f -c spec-build -n $NAMESPACE $JOB_NAME
                fi
                if [[ "$JOB_STATE" == "Failed" ]]; then
                    kubectl logs -f -c spec-build -n $NAMESPACE $JOB_NAME
                    echo "Job failed, exiting"
                    exit 1
                fi
                if [[ "$JOB_STATE" == "Succeeded" ]]; then
                    echo "Build succeded"
                fi
            done

            echo "Package $PACKAGE_CATEGORY/$PACKAGE_NAME @ $PACKAGE_VERSION built!"
            kubectl delete packagebuild -n $NAMESPACE $JOB_NAME
        done # Done waiting
    done
}

build() {
    PACKS=""
    # For each package in the tree, get the path where the spec resides
    # e.g. packages/acct-group/amavis/0/
    for i in $(echo "$PKG_LIST" | jq -rc '.packages[]'); do

        PACKAGE_PATH=$(echo "$i" | jq -r ".path")
        PACKAGE_NAME=$(echo "$i" | jq -r ".name")
        PACKAGE_CATEGORY=$(echo "$i" | jq -r ".category")
        PACKAGE_VERSION=$(echo "$i" | jq -r ".version")

        if [ $(mc ls minio-ci/$BUCKET/$PACKAGE_NAME\-$PACKAGE_CATEGORY\-$PACKAGE_VERSION.package | wc -l) != "0" ]; then
            echo "Package $PACKAGE_CATEGORY/$PACKAGE_NAME already present, skipping"
            continue
        fi

        PACKS="$PACKS $PACKAGE_CATEGORY/$PACKAGE_NAME"
    done

    if [[ -n "$PACKS" ]]; then
        if [[ "$SMART_BUILD" == "true" ]]; then
            smart_build "$PACKS"
        else
            parallel_build "$PACKS"
        fi
    else
        echo "No packages to build"
    fi
}

if hash stern 2>/dev/null; then
    if [[ "$TRACE_LOGS_BACKGROUND" == "true" ]]; then
        stern -n $NAMESPACE . > build.log &
    fi
fi

mc alias set minio-ci $MINIO_API_URL $MINIO_ACCESS_KEY $MINIO_SECRET_KEY

if [[ "$BUILD_PHASE" == "true" ]]; then
    build
fi

if [[ "$PRUNE_PHASE" == "true" ]]; then
    prune
fi

if [[ "$CREATE_PHASE" == "true" ]]; then
    create_repo
fi
